package tungsten.base.event;

import tungsten.base.thread.ThreadPool;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SingleEventDispatcher implements IEventDispatcher, Runnable
{
	/**
	 * 所有的Handle
	 */
	private Map<Integer, IEventHandler> handlerMap = new ConcurrentHashMap<>();
	/**
	 * 所有的事件缓冲队列
	 */
	private LinkedBlockingQueue<Event> events = new LinkedBlockingQueue<>();
	/**
	 * 缓冲队列的长度
	 */
	private AtomicInteger length = new AtomicInteger(0);
	/**
	 * 一个读写锁，用来同步 isAddToRun
	 */
	private ReadWriteLock lock = new ReentrantReadWriteLock();
	/**
	 * 标识是否已经加入到线程池之中
	 */
	private Boolean isAddToRun = false;
	
	public void addEventListener(int type, IEventHandler handler)
	{
		EventBus.addEventListener(type, this);
		handlerMap.put(type, handler);
	}

	public void removeEventListener(int type)
	{
		EventBus.removeEventListener(type, this);
		handlerMap.remove(type);
	}

	public void dispatchEvent(Event event)
	{
		EventBus.dispatchEvent(event);
	}

	@Override
	public void onEvent(Event event)
	{
		events.add(event);
		length.incrementAndGet();

		lock.readLock().lock();
		boolean __isAddRun = isAddToRun;
		lock.readLock().unlock();

		// 如果还没有加入到线程里面去的话
		if (__isAddRun == false) // 还没加入到线程池
		{
			boolean needAdd = false;
			synchronized (length)
			{
				if (isAddToRun == false)
				{
					needAdd = isAddToRun = true;
				}
			}
			if (needAdd)
			{
				ThreadPool.submit(EventBus.EVENT_THREAD,this);
			}
		}
	}

	private void checkAddToRun()
	{
		if (length.get() == 0)
		{
			lock.writeLock().lock();
			if (length.get() == 0)
			{
				isAddToRun = false;
			}
			else
			{
				ThreadPool.submit(EventBus.EVENT_THREAD,this);
			}
			lock.writeLock().unlock();
		}
		else
		{
			ThreadPool.submit(EventBus.EVENT_THREAD,this);
		}
	}
	
	@Override
	public void run()
	{
		while (true)
		{
			Event event = events.poll();
			if (event == null)
			{
				break;
			}
			length.decrementAndGet();

			try
			{
				IEventHandler handle = handlerMap.get(event.getType());

				if (handle != null)
				{
					handle.execute(event);
				}
			}
			catch (Exception e)
			{

			}
		}
		checkAddToRun();
	}
}
